<?php

/**
 * Created by PhpStorm.
 * Author: daisc
 * QQ: 2444329889
 * Time: 2017/09/28 9:50
 * Desc: 在线支付退款类
 */
class Pay_Online_Refund
{


    /**
     * @function 退款开始
     * @param $ordersn 订单号
     * @param $model 模型
     * @param $offline 线下退款
     * @params $refund_cost 退款金额
     */
    public static function refund_start($ordersn, $model, $offline = false, $refund_data = array(), $refund_cost = 0)
    {
        //判断订单是否已经退款
        if (self::_check_is_refund($ordersn)) {
            return true;
        }

        $order = Model_Member_Order::order_info($ordersn);

        //订单总价信息
        $total_info = Model_Member_Order_Compute::get_order_price($order['id']);
        if ($total_info && !empty($total_info['total_price'])) {
            $order['payprice'] = $total_info['pay_price'];
        }

        if (!$order['payprice']) {
            return true;
        }

        //判断是否为在线退款
        $online_transaction_no = json_decode($order['online_transaction_no'], true);
        if (empty($online_transaction_no) || $offline) {
            self::_refund_by_admin($order, $refund_data, $refund_cost);
            $org_status      = $order['status'];
            $order['status'] = 4;

            //退款,处理财务记录
            self::_make_finance($order, $model, $org_status, $refund_cost);

            //收支明细记录添加
            self::_add_finance_record($order, $refund_cost);

            // 秒杀数据回滚
            self::_seckill_refund_number_roll_back($order);

            return true;
        }
        $result = 2;
        if (isset($refund_data['refund_type'])) {
            $order['refund_type'] = $refund_data['refund_type'];
        }

        switch ($online_transaction_no['source']) {
            case 'wxpay':
                $result = self::_wxpay_refund($order, $online_transaction_no['transaction_no'], $refund_cost);
                break;
            case 'alipay':
                $result = self::_ailpay_refund($order, $online_transaction_no['transaction_no'], $refund_cost);
                break;
            case 'wxxcx':
                $result = self::_wxxcx_refund($order, $online_transaction_no['transaction_no'], $refund_cost);
                break;
            case 'allinpay':
                $result = self::_allinpay_refund($order, $refund_cost);
                break;
            case 'ttalipay':
            case 'ttweixin':
                $result = self::_toutiao_refund($order, $refund_cost, $refund_data['refund_reason']);
                break;
            case 'ttpay':
                $result = self::_toutiao_trade_refund($order, $refund_cost, $refund_data['refund_reason']);
                break;
            case 'wallet_pay':
                $result = 1;
                DB::update('wallet_log')->set(['refund_cost'=>$refund_cost])
                    ->where('order_sn','=',$order['ordersn'])
                    ->and_where('type','=',3)
                    ->execute();
                break;
            case 'icbcpay':
                $result = Service_Pay_Center::refund_order($order, $refund_cost);
                break;
        }

        if ($result == 1) {
            
            //退款成功,更改订单状态
            $rsn = DB::update('member_order')
                ->set(array('status' => 4))
                ->where('ordersn', '=', $ordersn)
                ->execute();
            if ($refund_data['refund_reason']) {

                DB::update('member_order')
                    ->set(array('refund_reason' => $refund_data['refund_reason']))
                    ->where('ordersn', '=', $ordersn)
                    ->execute();
            }

            if ($rsn) {
                $org_status      = $order['status'];
                $order['status'] = 4;

                //退款,处理财务记录
                self::_make_finance($order, $model, $org_status, $refund_cost);

                //收支明细记录添加
                self::_add_finance_record($order, $refund_cost);

                // 秒杀数据回滚
                self::_seckill_refund_number_roll_back($order);

                Model_Member_Order::back_order_status_changed($org_status, $order, $model);
            }
        }

        DB::update('member_order')
            ->set(array('online_refund_status' => $result))
            ->where('ordersn', '=', $ordersn)
            ->execute();

        return $result;
    }

    /**
     * 退款财务处理
     * @param $order
     * @param $model
     * @param $org_status
     * @param $refund_cost
     */
    private static function _make_finance($order, $model, $org_status, $refund_cost)
    {
        if (St_Functions::is_normal_app_install('supplierfinancemanage')) {
            if ($refund_cost > 0) {
                Model_Finance_Supplier::update_refund_cost($org_status, $order, $refund_cost);
            }
            Model_Finance_Supplier::refund_brokerage($org_status, $order, $model);
        }
        if ($refund_cost > 0) {
            Model_Member_Order_Compute::update_refund_cost($order['id'], $refund_cost);
        }
    }

    /**
     * 收支明细记录添加
     * @param $order
     * @param $refund_cost
     */
    private static function _add_finance_record($order, $refund_cost) {
        $refund_price = bcsub($order['payprice'],$refund_cost,2);
        $refund_msg = '订单'.$order['ordersn'].'退款成功'.$refund_price;
        $refund_msg.= $refund_cost>0?',手续费'.$refund_cost:'';
        Model_Finance_Record::add_finance_record($order['payprice'],2,'订单退款',$refund_msg,$order['ordersn']);
    }

    /**
     * 秒杀回滚
     * @param $order
     */
    private static function _seckill_refund_number_roll_back($order) {
        if (St_Functions::is_normal_app_install('seckill')) {
            $is_seckill = DB::select()->from('seckill_order')->where("ordersn={$order['ordersn']}")->execute()->current();
            if ($is_seckill) {
                Model_Seckill::refund_number_roll_back($order['id']);
            }
        }
    }

    private static function _toutiao_refund($order, $refund_cost = 0, $reason = '')
    {
        $ordersn               = $order['ordersn'];
        $toutiao_config_params = array(
            'cfg_toutiao_appid',
            'cfg_toutiao_danbao_salt',
            'cfg_toutiao_danbao_token',
            'cfg_m_main_url',
        );
        $config                = Model_Sysconfig::get_configs(0, $toutiao_config_params, 0);

        $online_transaction_no = json_decode($order['online_transaction_no'], true);
        //$online_transaction_no['source']='';
        $price        = $order['payprice'] * 100;
        $refund_price = intval($price - doubleval($refund_cost) * 100);
        //业务数据
        $params = array(
            'app_id' => $config['cfg_toutiao_appid'],
            'out_order_no' => $online_transaction_no['transaction_no'],    //商户唯一订单号
            'refund_amount' => $refund_price,
            'out_refund_no' => $ordersn . time(),
            'reason' => $reason ? $reason : '协商退款',
            'notify_url' => $config['cfg_m_main_url'] . '/phone/toutiao/mobile/index/refund_notify',
        );
        //公共请求参数
        $params['sign'] = self::getSign($params, $config['cfg_toutiao_danbao_salt']);

        $res = json_decode(self::httpPost('https://developer.toutiao.com/api/apps/ecpay/v1/create_refund', $params), true);
        if ($res['err_no'] == '0') {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 头条交易系统退款
     * @param $order_info
     * @param int $refund_cost
     * @param string $reason
     * @return array|bool|mixed|string
     * @throws Kohana_Exception
     */
    private static function _toutiao_trade_refund($order_info, $refund_cost = 0, $reason = '')
    {
        $version = Model_Toutiao_Pay_Log::get_version($order_info['ordersn']);
        if($version) {
            $trade_class = Model_Toutiao_Trade_Order_Factory::get_instance($version);
            if($trade_class) {
                $td_refund_no = DB::select('td_refund_no')->from('member_order_refund')
                    ->where('ordersn','=',$order_info['ordersn'])
                    ->execute()
                    ->get('td_refund_no');
                $out_refund_no = self::_get_refund_num($order_info, 'ttpay');
                if(empty($td_refund_no)){
                    $result = $trade_class->create_refund($order_info, $refund_cost, $out_refund_no);
                }else{
                    $result = $trade_class->merchant_audit_callback($out_refund_no);
                }
            }
            return $result['status'];
        }
        return false;
    }

    /**
     * 计算签名
     */
    private static function getSign($params, $salt)
    {
        unset($params["sign"]);
        unset($params["app_id"]);
        unset($params["thirdparty_id"]);
        $paramArray = array();
        foreach ($params as $param) {
            $paramArray[] = trim($param);
        }
        $paramArray[] = trim($salt);
        sort($paramArray, 2);
        $signStr = trim(implode('&', $paramArray));
        return md5($signStr);
    }

    private static function httpPost($url, $postfields = '')
    {
        $curl = curl_init();
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        if (!$postfields) {
            return 'data is null';
        }
        if (is_array($postfields)) {
            $postfields = json_encode($postfields, 320);
        }
        curl_setopt($curl, CURLOPT_POST, 1);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $postfields);
        curl_setopt($curl, CURLOPT_HEADER, 0);
        curl_setopt($curl, CURLOPT_HTTPHEADER, array(
            'Content-Type: application/json; charset=utf-8',
            'Content-Length:' . strlen($postfields),
            'Cache-Control: no-cache',
            'Pragma: no-cache'
        ));
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        $res = curl_exec($curl);
        curl_close($curl);
        return $res;
    }


    private static function _allinpay_refund($order, $refund_cost = 0)
    {


        if ($refund_cost > $order['payprice']) {
            return false;
        }
        $refund_price_cents = ($order['payprice'] - $refund_cost) * 100;
        $result_status      = false;
        $result_status      = self::_allinpay_cancel($refund_price_cents, $order['ordersn']);

        if (!$result_status) {
            $result_status = self::_allinpay_retreat($refund_price_cents, $order['ordersn']);
        }
        return $result_status;
    }

    //当天的用撤销
    private static function _allinpay_cancel($refund_price_cents, $reqsn)
    {

        $config              = Model_Sysconfig::get_configs(0, array('cfg_allinpay_cusid', 'cfg_allinpay_appid', 'cfg_allinpay_appkey'));
        $params              = array();
        $params["cusid"]     = $config['cfg_allinpay_cusid'];
        $params["appid"]     = $config['cfg_allinpay_appid'];
        $params["version"]   = Allinpay::APIVERSION;
        $params["trxamt"]    = $refund_price_cents;
        $params["reqsn"]     = $reqsn . "re";
        $params["randomstr"] = Allinpay::randomStr(10);
        $params["oldreqsn"]  = $reqsn;
        $params["sign"]      = Allinpay::SignArray($params, $config['cfg_allinpay_appkey']);//签名
        $paramsStr           = Allinpay::ToUrlParams($params);
        $url                 = Allinpay::APIURL . "/cancel";
        $rsp                 = self::request($url, $paramsStr);

        $rspArray = json_decode($rsp, true);
        if (Allinpay::validSign($rspArray, $config['cfg_allinpay_appkey'])) {
            if ($rspArray['trxstatus'] == '0000') {
                return true;
            }

        }
        return false;
    }

    //非当天的用退款
    private static function _allinpay_retreat($refund_price_cents, $reqsn)
    {
        $config              = Model_Sysconfig::get_configs(0, array('cfg_allinpay_cusid', 'cfg_allinpay_appid', 'cfg_allinpay_appkey'));
        $params              = array();
        $params["cusid"]     = $config['cfg_allinpay_cusid'];
        $params["appid"]     = $config['cfg_allinpay_appid'];
        $params["version"]   = Allinpay::APIVERSION;
        $params["trxamt"]    = $refund_price_cents;
        $params["reqsn"]     = $reqsn . "re";
        $params["randomstr"] = Allinpay::randomStr(10);
        $params["oldreqsn"]  = $reqsn;
        $params["sign"]      = Allinpay::SignArray($params, $config['cfg_allinpay_appkey']);//签名
        $paramsStr           = Allinpay::ToUrlParams($params);
        $url                 = Allinpay::APIURL . "/refund";
        $rsp                 = self::request($url, $paramsStr);

        $rspArray = json_decode($rsp, true);
        if (Allinpay::validSign($rspArray, $config['cfg_allinpay_appkey'])) {
            if ($rspArray['trxstatus'] == '0000') {
                return true;
            }
        }
        return false;
    }


    public static function request($url, $params)
    {
        $ch          = curl_init();
        $this_header = array("content-type: application/x-www-form-urlencoded;charset=UTF-8");
        curl_setopt($ch, CURLOPT_HTTPHEADER, $this_header);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)');
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);//如果不加验证,就设false,商户自行处理
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);

        $output = curl_exec($ch);
        curl_close($ch);
        return $output;
    }


    /**
     * @function 线下转账退款
     * @param $order
     */
    private static function _refund_by_admin($order, $refund_data = array(), $refund_cost)
    {
        $order['refund_proof']    = $refund_data['refund_proof'];
        $order['refund_type']     = $refund_data['refund_type'];
        $order['refund_platform'] = $refund_data['refund_platform'];
        self::_update_refunf_log($order, 1, '', '管理员已同意退款,等待退款转出', 'bank', $refund_cost);//更新退款信息

    }


    /**
     * @function 支付宝退款
     * @param $order 订单
     * @param $transaction_no 交易流水号
     */
    private static function _ailpay_refund($order, $transaction_no, $refund_cost = 0)
    {

        require_once TOOLS_PATH . 'lib/alipay_refund/AlipayTradeService.php';
        require_once TOOLS_PATH . 'lib/alipay_refund/AopClient.php';
        require_once TOOLS_PATH . 'lib/alipay_refund/SignData.php';
        require_once TOOLS_PATH . 'lib/alipay_refund/AlipayTradeRefundRequest.php';
        require_once TOOLS_PATH . 'lib/alipay_refund/AlipayTradeRefundContentBuilder.php';
        $alipay_config  = self::_alipay_config();
        $batch_no       = self::_get_refund_num($order, 'alipay');//退款批次号
        $RequestBuilder = new AlipayTradeRefundContentBuilder();
        $RequestBuilder->setOutTradeNo($order['ordersn']);//订单号
        $RequestBuilder->setTradeNo($transaction_no);//支付宝流水号

        $refund_price = $order['payprice'] - $refund_cost;
        $RequestBuilder->setRefundAmount($refund_price);//退款金额


        $RequestBuilder->setOutRequestNo($batch_no);//退款标识
        $RequestBuilder->setRefundReason('协商退款');
        $aop      = new AlipayTradeService($alipay_config);
        $response = $aop->Refund($RequestBuilder);
        $status   = 2;
        if (($response->code == '10000') && ($response->msg == 'Success')) {
            $reason = '已退款到支付宝支付账号' . $response->buyer_logon_id;
            $status = 1;
        } else {
            $reason = $response->msg;
        }
        self::_update_refunf_log($order, $status, $batch_no, $reason, 'alipay', $refund_cost);//更新退款信息
        return $status;


    }


    /**
     * @function 微信退款
     * @param $order 订单
     * @param $transaction_no 交易流水号
     */
    private static function _wxpay_refund($order, $transaction_no, $refund_cost = 0)
    {
        if (empty($transaction_no)) {
            return false;
        }

        if ($refund_cost > $order['payprice']) {
            return false;
        }

        self::_set_wxpay_config();//配置微信支付账号等
        $price         = $order['payprice'] * 100;
        $refund_price  = $price - doubleval($refund_cost) * 100;
        $out_refund_no = self::_get_refund_num($order, 'wxpay');
        $input         = new WxPayRefund();
        //$input->SetOut_trade_no($order['ordersn']);         //自己的订单号
        $input->SetTransaction_id($transaction_no);     //微信官方生成的订单流水号，在支付成功中有返回
        $input->SetOut_refund_no($out_refund_no);         //退款单号
        $input->SetTotal_fee($price);         //订单标价金额，单位为分
        $input->SetRefund_fee($refund_price);         //退款总金额，订单总金额，单位为分，只能为整数
        $input->SetOp_user_id(MCHID);
        $result = WxPayApi::refund($input); //退款操作
        $status = 2;
        $reason = '微信退款未知错误,请联系管理员';
        if (($result['return_code'] == 'SUCCESS') && ($result['result_code'] == 'SUCCESS' || $result['err_code_des'] == '订单已全额退款')) {
            $reason = '已退款到微信支付原账号';
            $status = 1;
        } else if
        (($result['return_code'] == 'FAIL') || ($result['result_code'] == 'FAIL')) {
            $reason = (empty($result['err_code_des']) ? $result['return_msg'] : $result['err_code_des']);
        }
        self::_update_refunf_log($order, $status, $out_refund_no, $reason, 'wxpay', $refund_cost);//更新退款信息
        return $status;
    }

    /**
     * @function 微信小程序退款
     * @param $order 订单
     * @param $transaction_no 交易流水号
     */
    private static function _wxxcx_refund($order, $transaction_no, $refund_cost = 0)
    {
        if (empty($transaction_no)) {
            return false;
        }

        if ($refund_cost > $order['payprice']) {
            return false;
        }
        $dir      = rtrim(BASEPATH, DIRECTORY_SEPARATOR);
        $file_dir = $dir . "/res/vendor/wxxcx/lib/WxPay.Api.php";
        require_once $file_dir;

        $xcx_wxpay_data = DB::select()->from('xcx_wxpay_data')->where('orderid', '=', $order['id'])->execute()->current();
        define("KEY", $xcx_wxpay_data['mch_key']);
        $price         = $order['payprice'] * 100;
        $refund_price  = $price - doubleval($refund_cost) * 100;
        $out_refund_no = self::_get_refund_num($order, 'wxxcx');
        $input         = new WxPayRefund();

        $input->SetAppid($xcx_wxpay_data['appid']);                           // 小程序APPID
        $input->SetMch_id($xcx_wxpay_data['mch_id']);                         // 商户号
        $input->SetTransaction_id($xcx_wxpay_data['transaction_id']);         // 微信官方生成的订单流水号，在支付成功中有返回
        $input->SetOut_refund_no($out_refund_no);                             // 退款单号
        $input->SetTotal_fee($price);                                         // 订单标价金额，单位为分
        $input->SetRefund_fee($refund_price);                                 // 退款总金额，订单总金额，单位为分，只能为整数
        $input->SetOp_user_id($xcx_wxpay_data['mch_id']);

        $result = WxPayApi::refund($input); //退款操作
        $status = 2;
        $reason = '微信小程序退款未知错误,请联系管理员';

        if (($result['return_code'] == 'SUCCESS') && ($result['result_code'] == 'SUCCESS' || $result['err_code_des'] == '订单已全额退款')) {
            $reason = '已退款到微信小程序支付原账号';
            $status = 1;
        } else if (($result['return_code'] == 'FAIL') || ($result['result_code'] == 'FAIL')) {
            $reason = (empty($result['err_code_des']) ? $result['return_msg'] : $result['err_code_des']);
        }
        self::_update_refunf_log($order, $status, $out_refund_no, $reason, 'wxxcx', $refund_cost);//更新退款信息
        return $status;
    }

    /**
     * @function  判断订单是否已经退款
     * @param $ordersn
     */
    private static function _check_is_refund($ordersn)
    {
        return DB::select('id')
            ->from('member_order_refund')
            ->where('ordersn', '=', $ordersn)
            ->where('status', '=', 1)
            ->execute()->get('id');
    }


    /**
     * @function 获取退款单号
     * @param $order
     * @param $type
     */
    private static function _get_refund_num($order, $type)
    {
        $refund_no = DB::select('refund_no')
            ->from('member_order_refund')
            ->where('ordersn', '=', $order['ordersn'])
            ->execute()->get('refund_no');
        if ($refund_no) {
            return $refund_no;
        }
        $func = '_get_' . $type . '_refund_num';
        return call_user_func(array('Pay_Online_Refund', $func), $order['ordersn']);

    }


    /**
     * @function 微信生成退款单号
     * @param $ordersn
     * @return string
     */
    private static function _get_wxpay_refund_num($ordersn)
    {
        $order_length = strlen($ordersn);
        $out_length   = 64 - $order_length;
        $chars        = md5($ordersn) . md5(strrev($ordersn));
        for ($i = 0; $i < $out_length; $i++) {
            $ordersn .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $ordersn;

    }

    /**
     * @function 微信小程序生成退款单号
     * @param $ordersn
     * @return string
     */
    private static function _get_wxxcx_refund_num($ordersn)
    {
        $order_length = strlen($ordersn);
        $out_length   = 64 - $order_length;
        $chars        = md5($ordersn) . md5(strrev($ordersn));
        for ($i = 0; $i < $out_length; $i++) {
            $ordersn .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $ordersn;

    }

    /**
     * @function 支付宝生成退款单号
     * @param $ordersn
     * @return mixed
     */
    private static function _get_alipay_refund_num($ordersn)
    {
        $batch_no = date('Ymd');
        return $batch_no . $ordersn;
    }

    /**
     * @function 微信小程序生成退款单号
     * @param $ordersn
     * @return string
     */
    private static function _get_ttpay_refund_num($ordersn)
    {
        $order_length = strlen($ordersn);
        $out_length   = 64 - $order_length;
        $chars        = md5($ordersn) . md5(strrev($ordersn));
        for ($i = 0; $i < $out_length; $i++) {
            $ordersn .= $chars[mt_rand(0, strlen($chars) - 1)];
        }
        return $ordersn;
    }

    /**
     * @function 微信退款初始化
     */
    private static function _set_wxpay_config()
    {

        //绑定支付的APPID
        define('APPID', self::_get_config_val('cfg_wxpay_appid'));
        //商户号
        define('MCHID', self::_get_config_val('cfg_wxpay_mchid'));
        //商户支付密钥
        define('KEY', self::_get_config_val('cfg_wxpay_key'));
        //公众帐号secert
        define('APPSECRET', self::_get_config_val('cfg_wxpay_appsecret'));


        $ext_dir = self::_get_ext_dir('wxpay');//微信文件所在路径

        define('SSLCERT_PATH', $ext_dir . '/vendor/pc/wxpay/cert/apiclient_cert.pem');
        define('SSLKEY_PATH', $ext_dir . '/vendor/pc/wxpay/cert/apiclient_key.pem');
        $file_dir = $ext_dir . "/vendor/pc/wxpay/lib/WxPay.Api.php";
        require_once $file_dir;
    }


    /**
     * @function 获取支付应用的路径
     * @param $source
     */
    private static function _get_ext_dir($source)
    {
        //证书路径,注意应该填写绝对路径
        $dir      = rtrim(BASEPATH, DIRECTORY_SEPARATOR);
        $issystem = DB::select('issystem')
            ->from('payset')
            ->where('pinyin', '=', $source)
            ->execute()->get('issystem');
        if ($issystem != 1) {
            $dir .= '/plugins/' . $source;
        } else {
            $dir .= '/payment/application';
        }
        return $dir;
    }

    //更新退款记录
    public static function update_refund_log($order, $status, $refund_no, $description, $platform, $refund_cost = 0)
    {
        return self::_update_refunf_log($order, $status, $refund_no, $description, $platform, $refund_cost);
    }


    /**
     * @function 更新退款记录
     * @param $order 订单
     * @param $status 退款状态
     * @param $refund_no 退款流水号
     * @param $description 说明
     * @param $platform 退款平台
     * @params $refund_cost 退款手续费
     */
    private static function _update_refunf_log($order, $status, $refund_no, $description, $platform, $refund_cost = 0)
    {
        $old_log = DB::select()
            ->from('member_order_refund')
            ->where('ordersn', '=', $order['ordersn'])
            ->execute()->current();
        $log     = array(
            'status' => $status,
            'refund_no' => $refund_no,
            'description' => $description,
            'modtime' => time(),
        );
        if ($old_log) {
            $log['addtime']    = $old_log['addtime'];
            $log['ordersn']    = $old_log['ordersn'];
            $log['platform']   = $old_log['platform'];
            $log['refund_fee'] = $order['payprice'] - $refund_cost;;
            $log['memberid'] = $old_log['memberid'];
            DB::delete('member_order_refund')->where('id', '=', $old_log['id'])->execute();
        } else {
            $log['addtime']      = time();
            $log['ordersn']      = $order['ordersn'];
            $log['platform']     = $platform;
            $log['refund_fee']   = $order['payprice'] - $refund_cost;
            $log['memberid']     = $order['memberid'];
            $log['refund_proof'] = $order['refund_proof'] ? $order['refund_proof'] : '';

            $log['platform'] = $order['refund_platform'] ? $order['refund_platform'] : '';

        }
        if (isset($order['refund_type'])) {
            $log['refund_type'] = $order['refund_type'];
        }
        self::add_refund_log($log);

    }


    /**
     * @function 添加退款日志
     * @param $log
     */
    public static function add_refund_log($log)
    {
        return DB::insert('member_order_refund', array_keys($log))
            ->values(array_values($log))
            ->execute();
    }


    /**
     * @function 整合支付宝配置
     * @return mixed
     */
    private static function _alipay_config()
    {
        $ext_dir                   = self::_get_ext_dir('alipay');
        $merchant_private_key_path = $ext_dir . '/vendor/pc/alipay_cash/rsa_private_key.pem';
        $alipay_public_key_path    = $ext_dir . '/vendor/pc/alipay_cash/rsa_public_key.pem';
        $merchant_private_key      = Model_Sysconfig::get_sys_conf('value', 'merchant_private_key');
        $alipay_public_key         = Model_Sysconfig::get_sys_conf('value', 'alipay_public_key');
        //合作身份者id
        $alipay_config['app_id'] = self::_get_config_val('cfg_alipay_appid');
        //商户私钥
        //如果没有秘钥值，那么读取文件
        if ($merchant_private_key) {
            $alipay_config['merchant_private_key'] = $merchant_private_key;
        } else {
            $alipay_config['merchant_private_key_path'] = $merchant_private_key_path;
        }
        //支付宝公钥
        if ($alipay_public_key) {
            $alipay_config['alipay_public_key'] = $alipay_public_key;
        } else {
            $alipay_config['alipay_public_key_path'] = $alipay_public_key_path;
        }
        //字符编码格式
        $alipay_config['charset'] = strtolower('utf-8');
        //签名方式
        $alipay_config['sign_type'] = strtoupper('RSA2');
        //签名
        $alipay_config['sign'] = strtoupper('MD5');
        //支付宝网关
        $alipay_config['gatewayUrl'] = 'https://openapi.alipay.com/gateway.do';


        return $alipay_config;
    }


    /**
     * @function 获取参数的值
     */
    private static function _get_config_val($field)
    {

        return DB::select('value')
            ->from('sysconfig')
            ->where('varname', '=', $field)
            ->execute()->get('value');
    }


    /**
     * @function 前台用户申请退款
     * @param $data
     * @param $memberid
     */
    public static function apply_order_refund($data, $memberid, $model)
    {
        $refund_reason  = trim(Common::remove_xss($data['refund_reason']));
        $platform       = trim(Common::remove_xss($data['platform']));
        $ordersn        = trim(Common::remove_xss($data['ordersn']));
        $alipay_account = '';
        $cardholder     = '';
        $cardnum        = '';
        $bank           = '';

        if (strlen($refund_reason) < 5) {
            return array('status' => 0, 'message' => '退款原因不能少于5个字');
        }

        if (empty($ordersn)) {
            return array('status' => 0, 'message' => '订单号错误');
        }
        $info = Model_Member_Order::order_info($ordersn, $memberid);

        if ($info['refund_restriction'] == 1) {
            return array('status' => 0, 'message' => '不可退款');
        }

        if (empty($info) || $info['status'] != 2) {
            if ($info['status'] != 0 && $info['ispay'] != 1 && empty($info['online_transaction_no'])) {//再次判断是否是，已支付待二次确认的订单，不是就不能退款
                return array('status' => 0, 'message' => '订单号错误');
            }
        }

        $online_transaction_no = json_decode($info['online_transaction_no'], true);

        //退款到指定账户
        if (empty($online_transaction_no)) {
            if ($platform == 'alipay') {
                $alipay_account = trim(Common::remove_xss($data['alipay_account']));
                $platform       = 'other_alipay';
                if (!$alipay_account) {
                    return array('status' => 0, 'message' => '请输入正确的支付宝账号');
                }
            } elseif ($platform == 'bank') {
                $cardholder = trim(Common::remove_xss($data['cardholder']));
                $cardnum    = trim(Common::remove_xss($data['cardnum']));
                $bank       = trim(Common::remove_xss($data['bank']));
                if (empty($cardholder) || empty($cardnum) || empty($bank)) {
                    return array('status' => 0, 'message' => '请输入正确的银行卡信息');
                }
            }
        } else {
            //原路退还
            $platform = $online_transaction_no['source'];
        }

        // 如果是有条件退款
        $refund_cost = 0; // 退款手续费默认 0
        $refund_fee = $info['payprice'];
        try {
            if ($info['refund_restriction'] == 2) {
                $refund_rule_class = Service_Refund_Rule_Factory::get_instance($info['typeid']);
                if ($refund_rule_class) {
                    $refund_cost = $refund_rule_class->get_refund_cost($info['id'], $info['payprice'], array('usedate' => $info['usedate']));
                    $refund_fee = bcsub($refund_fee, $refund_cost, 2);
                }
            }
        } catch (Exception $e) {

        }

        $log = array(
            'ordersn' => $ordersn,
            'platform' => $platform ? $platform : 'alipay',
            'refund_fee' => $refund_fee,
            'status' => 0,
            'addtime' => time(),
            'memberid' => $memberid,
            'alipay_account' => $alipay_account,
            'cardholder' => $cardholder,
            'cardnum' => $cardnum,
            'bank' => $bank,
        );
        if(isset($data['pay_type']) && $data['pay_type'] == 'ttpay'){
            $log['refund_no'] = self::_get_refund_num($info,'ttpay');
            $log['td_refund_no'] = $data['refund_id'];
        }
        DB::delete('member_order_refund')->where('ordersn', '=', $ordersn)->execute();
        if (self::add_refund_log($log)) {
			// 更新订单收益
            DB::update('member_order_compute')
                ->set(array('refund_cost' => $refund_cost))
                ->where('order_id', '=', $info['id'])
                ->execute();

            // 更新订单信息
            $update = array(
                'status' => 6,
                'refund_reason' => $refund_reason,
            );
            //无需审核，自动退款，且是线上付款
            if($info['no_confirm_refund']>0 && time()<$info['no_confirm_refund'] && $info['online_transaction_no'] != ''  ){

                $refund_cost = 0;
                $data['refund_reason'] = $refund_reason;
                //如果在线交易号不为空,则执行线上退款操作.
                $offline = false;
                $refund_data = array(
                    'refund_reason' => $refund_reason,
                    'refund_platform' => '原路退回',
                    'refund_type' => 1,
                );
                $table_field = St_Functions::table_field($info['typeid']);
                $table = $table_field[3]=='model_archive'?'tongyong':$table_field[3];
                $model = 'Model_'.ucfirst($table);
                $refund_result = self::refund_start($info['ordersn'],$model,$offline,$refund_data,$refund_cost);
                if ($refund_result==2){
                    return array('status' => 0, 'message' => '自动退款失败');
                }
                $message = "自动退款成功!";
                $update = array(
                    'status' => 4,
                    'refund_reason' => $refund_reason,
                );
            }else{
                $message = "退款请求提交成功，等待商家确认!";
                $update = array(
                    'status' => 6,
                    'refund_reason' => $refund_reason,
                );
            }
            DB::update('member_order')->set(['supplier_viewstatus'=>0])->where('ordersn', '=', $ordersn)->execute();

            DB::update('member_order')->set($update)->where('ordersn', '=', $ordersn)->execute();
            $order = Model_Member_Order::order_info($ordersn);
            Model_Member_Order::back_order_status_changed($info['status'], $order, $model);
            return array('status' => 1, 'message' => $message);
        } else {
            return array('status' => 0, 'message' => '未知错误');
        }

    }


    /**
     * @function 撤销订单退款
     * @param $ordersn
     * @param $memberid
     */
    public static function order_refund_back($ordersn, $memberid, $model)
    {
        $order = DB::select()->from('member_order')->where('memberid', '=', $memberid)->and_where('ordersn', '=', $ordersn)->execute()->current();
        if (!$order) {
            return array('bool' => false, 'message' => __('订单不存在'));
        }

        $result = array('bool' => true, 'message' => __('不同意您的申请，详情请联系商家'));
        if ($order['status'] == 6) {
            $row = DB::update('member_order')->set(array('status' => 2))->where('id', '=', $order['id'])->execute();
            if ($row) {
                $order['status'] = 2;
                self::_refund_back_log($ordersn);
                Model_Member_Order::back_order_status_changed(6, $order, $model);

                $result = array('bool' => true, 'message' => __('商家同意您的申请'));
            }
        } else if ($order['status'] == 4) {
            $result = array('bool' => false, 'message' => __('商家已退款，您的申请未通过'));
        }
        return $result;

    }


    /**
     * @function 撤销退款
     * @param $ordersn
     */
    private static function _refund_back_log($ordersn)
    {
        $update = array(
            'status' => 2,
            'description' => '用户撤销退款申请',
        );
        DB::update('member_order_refund')->set($update)->where('ordersn', '=', $ordersn)->execute();

    }


    /**
     * @function 增加 订单退款信息
     * @param $info
     */
    public static function get_refund_info($info)
    {
        if ($info['status'] == 4 || $info['status'] == 6) {
            $info['refund'] = DB::select()
                ->from('member_order_refund')
                ->where('ordersn', '=', $info['ordersn'])
                ->order_by('addtime', 'desc')
                ->limit(1)
                ->execute()->current();
            switch ($info['refund']['platform']) {
                case 'alipay':
                    $info['refund']['platform'] = '支付宝';
                    break;
                case 'other_alipay':
                    $info['refund']['platform'] = '支付宝';
                    break;
                case 'wxpay':
                    $info['refund']['platform'] = '微信';
                    break;
                case 'bank':
                    $info['refund']['platform'] = '银行卡';
                    break;
                case 'wallet_pay':
                    $info['refund']['platform'] = '余额';
                    break;
            }

            $info['refund']['refund_reason'] = $info['refund_reason'];
            unset($info['refund_reason']);
        }
        return $info;

    }


    /**
     * @function 拒绝退款
     * @param $ordersn 订单号
     * @param $model 模型
     * @param $description 拒绝理由
     */
    public static function admin_refund_back($ordersn, $model, $description)
    {
        $order = Model_Member_Order::order_info($ordersn);
        $rsn   = DB::update('member_order')
            ->set(array('status' => 2))
            ->where('ordersn', '=', $ordersn)
            ->execute();
        if ($rsn) {
            $org_status      = $order['status'];
            $order['status'] = 2;
            Model_Member_Order::back_order_status_changed($org_status, $order, $model);
            self::_update_last_log($org_status, $order, $description);

            if ($order['paysource'] == '抖音支付') {
                //抖音退款单做同步处理
                $td_refund_no = DB::select('td_refund_no')
                    ->from('member_order_refund')
                    ->where('ordersn', '=', $ordersn)
                    ->execute()
                    ->get('td_refund_no');
                if (!empty($td_refund_no)) {
                    $description = empty($description) ? '商家拒绝退款' : $description;
                    $trade_class = Model_Toutiao_Trade_Order_Factory::get_instance(2);
                    $trade_class->merchant_audit_callback($ordersn, 2, $description);
                }
            }
        }
        return true;
    }


    /**
     * @function 更新最后一个日志记录
     * @param $org_status
     * @param $order
     * @param $description
     */
    private static function _update_last_log($org_status, $order, $description)
    {
        $description = '商家拒绝了您的退款申请，原因:' . $description;
        $lastid      = DB::select('id')
            ->from('member_order_log')
            ->where('orderid', '=', $order['id'])
            ->and_where('prev_status', '=', $org_status)
            ->and_where('current_status', '=', $order['status'])
            ->order_by('addtime', 'desc')
            ->limit(1)
            ->execute()
            ->get('id');
        DB::update('member_order_log')
            ->set(array('description' => $description))
            ->where('id', '=', $lastid)
            ->execute();
    }


}